package web.suzy.oj.manager.msg;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import web.suzy.oj.common.exception.StatusFailException;
import web.suzy.oj.dao.msg.AdminSysNoticeEntityService;
import web.suzy.oj.dao.msg.UserSysNoticeEntityService;
import web.suzy.oj.dao.user.SessionEntityService;
import web.suzy.oj.pojo.entity.msg.AdminSysNotice;
import web.suzy.oj.pojo.entity.msg.UserSysNotice;
import web.suzy.oj.pojo.entity.user.Session;
import web.suzy.oj.pojo.vo.AdminSysNoticeVO;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * YangSuzy 软件工作室
 * 类名: AdminNoticeManager
 * 描述: ---- 待定 -----
 * 功能: ---- 待定 -----
 *
 * @author YangSuzy
 * Date: 2022/11/18 16:36
 */
@Component
@Slf4j(topic = "suzyoj")
public class AdminNoticeManager {
    @Resource
    private AdminSysNoticeEntityService adminSysNoticeEntityService;

    @Resource
    private UserSysNoticeEntityService userSysNoticeEntityService;

    @Resource
    private SessionEntityService sessionEntityService;

    /**
     * 方法名: getSysNotice
     * 描述: 获取系统消息
     *
     * @param limit       每页显示数量
     * @param currentPage 当前页
     * @param type        消息类型
     * @return com.baomidou.mybatisplus.core.metadata.IPage<web.suzy.oj.pojo.vo.AdminSysNoticeVO>
     * @date 2022/11/18 16:42
     * @auther YangSuzy
     **/
    public IPage<AdminSysNoticeVO> getSysNotice(Integer limit, Integer currentPage, String type) {
        //设置默认页
        if (currentPage == null || currentPage < 1) {
            currentPage = 1;
        }
        //设置每页默认显示数量
        if (limit == null || limit < 1) {
            limit = 5;
        }
        return adminSysNoticeEntityService.getSysNotice(limit, currentPage, type);
    }

    /**
     * 方法名: addSysNotice
     * 描述: 发布系统消息
     *
     * @param adminSysNotice 管理员系统消息
     * @return void
     * @date 2022/11/18 16:53
     * @auther YangSuzy
     **/
    public void addSysNotice(AdminSysNotice adminSysNotice) throws StatusFailException {
        boolean isOk = adminSysNoticeEntityService.saveOrUpdate(adminSysNotice);
        //向所有登录过的用户异步发送通知
        this.syncNoticeToLoggedUser();
        if (!isOk) {
            throw new StatusFailException("发布失败");
        }
    }

    /**
     * 方法名: deleteSysNotice
     * 描述: 删除系统消息
     *
     * @param id 消息ID
     * @return void
     * @date 2022/11/18 17:05
     * @auther YangSuzy
     **/
    public void deleteSysNotice(Long id) throws StatusFailException {
        boolean isOk = adminSysNoticeEntityService.removeById(id);
        if (!isOk) {
            throw new StatusFailException("删除失败");
        }
    }

    /**
     * 方法名: updateSysNotice
     * 描述: 更新系统消息
     *
     * @param adminSysNotice 系统消息
     * @return void
     * @date 2022/11/18 17:10
     * @auther YangSuzy
     **/
    public void updateSysNotice(AdminSysNotice adminSysNotice) throws StatusFailException {
        boolean isOk = adminSysNoticeEntityService.saveOrUpdate(adminSysNotice);
        //向所有登录过的用户异步发送通知
        this.syncNoticeToLoggedUser();
        if (!isOk) {
            throw new StatusFailException("更新失败");
        }
    }

    /**
     * 方法名: syncNoticeToNewRegisterBatchUser
     * 描述: 异步方法 - 发送消息给新批量注册的用户
     *
     * @param uidList 用户ID列表
     * @return void
     * @date 2022/11/27 16:57
     * @auther YangSuzy
     **/
    @Async
    public void syncNoticeToNewRegisterBatchUser(List<String> uidList) {
        QueryWrapper<AdminSysNotice> adminSysNoticeQueryWrapper = new QueryWrapper<>();
        //查询要发送的消息
        adminSysNoticeQueryWrapper
                //发送给所有用户的
                .eq("type", "All")
                //今天之前发布的
                .le("create_time", new Date())
                //未删除的
                .eq("state", true);
        List<AdminSysNotice> adminSysNotices = adminSysNoticeEntityService.list(adminSysNoticeQueryWrapper);
        if (adminSysNotices.size() == 0) {
            return;
        }
        List<UserSysNotice> userSysNoticeList = new ArrayList<>();
        for (String uid : uidList) {
            for (AdminSysNotice adminSysNotice : adminSysNotices) {
                UserSysNotice userSysNotice = new UserSysNotice();
                //设置消息类型为系统通知
                userSysNotice.setType("Sys")
                        .setSysNoticeId(adminSysNotice.getId())
                        .setRecipientId(uid);
                userSysNoticeList.add(userSysNotice);
            }
        }
        userSysNoticeEntityService.saveOrUpdateBatch(userSysNoticeList);
    }

    /**
     * 方法名: addSingleNoticeToUser
     * 描述: 异步方法 - 发送单条消息给指定用户
     *
     * @param adminId     管理员ID
     * @param recipientId 接收方ID
     * @param title       消息标题
     * @param content     消息内容
     * @param type        消息类型
     * @return void
     * @date 2022/11/27 18:18
     * @auther YangSuzy
     **/
    @Transactional(rollbackFor = Exception.class)
    @Async
    public void addSingleNoticeToUser(String adminId, String recipientId, String title, String content, String type) {
        AdminSysNotice adminSysNotice = new AdminSysNotice();
        //设置发送的管理员ID
        adminSysNotice.setAdminId(adminId)
                //设置发送用户类型：单个用户
                .setType("Single")
                //设置消息标题
                .setTitle(title)
                //设置消息内容
                .setContent(content)
                //设置消息可见状态
                .setState(true)
                //设置接收方ID
                .setRecipientId(recipientId);
        boolean isOk = adminSysNoticeEntityService.save(adminSysNotice);
        //管理员保存消息成功后同事保存在用户消息中
        if (isOk) {
            UserSysNotice userSysNotice = new UserSysNotice();
            //设置接收方ID
            userSysNotice.setRecipientId(recipientId)
                    //设置系统通知ID
                    .setSysNoticeId(adminSysNotice.getId())
                    //设置消息类型：系统消息
                    .setType(type);
            userSysNoticeEntityService.save(userSysNotice);
        }
    }

    /**
     * 方法名: syncNoticeToLoggedUser
     * 描述: 异步方法，将管理员发布的系统通知推送给所有用户（只推送给登录过的用户）
     *
     * @return void
     * @date 2022/12/9 17:06
     * @auther YangSuzy
     **/
    @Transactional(rollbackFor = Exception.class)
    @Async
    public void syncNoticeToLoggedUser() throws StatusFailException {
        //查询所有未推送的系统通知
        QueryWrapper<AdminSysNotice> adminSysNoticeQueryWrapper = new QueryWrapper<>();
        adminSysNoticeQueryWrapper.eq("state", false);
        List<AdminSysNotice> adminSysNotices = adminSysNoticeEntityService.list(adminSysNoticeQueryWrapper);
        //没有未推送的通知则直接退出
        if (adminSysNotices.size() == 0) {
            return;
        }
        //查询所有登录过的用户登录会话记录并过滤重复数据
        QueryWrapper<Session> sessionQueryWrapper = new QueryWrapper<>();
        sessionQueryWrapper.select("DISTINCT uid");
        List<Session> sessionList = sessionEntityService.list(sessionQueryWrapper);
        //根据会话记录查询用户ID
        List<String> userIds = sessionList.stream().map(Session::getUid).collect(Collectors.toList());

        for (AdminSysNotice adminSysNotice : adminSysNotices) {
            switch (adminSysNotice.getType()) {
                //向所有用户推送系统通知
                case "All":
                    List<UserSysNotice> userSysNoticeList = new ArrayList<>();
                    for (String uid : userIds) {
                        UserSysNotice userSysNotice = new UserSysNotice();
                        userSysNotice.setRecipientId(uid)
                                .setType("Sys")
                                .setSysNoticeId(adminSysNotice.getId());
                        userSysNoticeList.add(userSysNotice);
                    }
                    boolean isOk1 = userSysNoticeEntityService.saveOrUpdateBatch(userSysNoticeList);
                    if (isOk1) {
                        //推送成功修改消息状态
                        adminSysNotice.setState(true);
                    }
                    break;
                //向单个用户推送我的通知
                case "Single":
                    UserSysNotice userSysNotice = new UserSysNotice();
                    userSysNotice.setRecipientId(adminSysNotice.getRecipientId())
                            .setType("Mine")
                            .setSysNoticeId(adminSysNotice.getId());
                    boolean isOk2 = userSysNoticeEntityService.saveOrUpdate(userSysNotice);
                    if (isOk2) {
                        //推送成功修改消息状态
                        adminSysNotice.setState(true);
                    }
                    break;
                default:
                    break;
            }
        }
        boolean isUpdateNoticeOk = adminSysNoticeEntityService.saveOrUpdateBatch(adminSysNotices);
        if (!isUpdateNoticeOk) {
            log.error("=============推送系统通知更新状态失败===============");
            throw new StatusFailException("系统通知推送失败");
        }
    }
}
